package org.iwidget.desktop.ui;

import org.iwidget.desktop.core.Iwidget;
import org.iwidget.desktop.model.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.*;
import javax.swing.*;
import javax.swing.filechooser.FileFilter;

/**
 *
 * @author Muhammad Hakim A
 */
public class FormFrame extends JPanel
        implements ActionListener {

    class MyButton extends JButton {

        private static final long serialVersionUID = 0x3836343134383437L;
        JTextField field;

        public MyButton(JTextField field, String string) {
            super(string);
            this.field = field;
        }
    }

    class MyFilter extends FileFilter {

        public boolean accept(File file) {
            return file.getName().endsWith(fileType);
        }

        public String getDescription() {
            return "*" + fileType;
        }
        String fileType;

        public MyFilter(String fileType) {
            this.fileType = fileType;
        }
    }

    public FormFrame(WidgetElement widget, ElementPreferences formFields[], String title, String saveLabel, String cancelLabel) {
        this.widget = widget;
        this.formFields = formFields;
        componentList = new ArrayList();
        setLayout(new BorderLayout());
        buildPreferencePanel();
        JPanel p = new JPanel();
        add(p, "South");

        JButton saveButton = new JButton();
        if (saveLabel == null) {
            saveButton.setText("Save");
        } else {
            saveButton.setText(saveLabel);
        }

        saveButton.setActionCommand("Save");
        saveButton.addActionListener(this);
        p.add(saveButton);

        JButton cancelButton = new JButton();
        if (cancelLabel == null) {
            cancelButton.setText("Cancel");
        } else {
            cancelButton.setText(cancelLabel);
        }
        cancelButton.setActionCommand("Cancel");
        cancelButton.addActionListener(this);
        p.add(cancelButton);
    }

    public static String getForm(WidgetElement widget, ElementPreferences formFields[], String title, String saveLabel, String cancelLabel) {
        FormFrame form = new FormFrame(widget, formFields, title, saveLabel, cancelLabel);
        JDialog dialog = new JDialog();
        dialog.getContentPane().add(form);
        form.dialog = dialog;
        dialog.setSize(350, calculateHeight(widget, formFields) + 95);
        Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
        int x = widget.getWindowJS().getX();
        if (x < 0) {
            x = 0;
        }
        if (x + 350 > screen.width) {
            x = screen.width - 350;
        }
        int y = widget.getWindowJS().getY() + widget.getWindowJS().getHeight();
        if (y < 0) {
            y = 0;
        }
        if (y + widget.getPreferenceObjects().size() * 40 + 120 > screen.height) {
            y = widget.getWindowJS().getY() - (widget.getPreferenceObjects().size() * 40 + 100);
        }
        dialog.setTitle(title);
        dialog.setResizable(false);
        dialog.setLocation(x, y);
        dialog.setModal(true);
        dialog.show();
        dialog.dispose();
        return form.result;
    }

    private static int calculateHeight(WidgetElement widget, ElementPreferences formFields[]) {
        int height = 0;
        for (int iCtr = 0; iCtr < formFields.length; iCtr++) {
            ElementPreferences item = formFields[iCtr];
            if (!item.getVisible()) {
                continue;
            }
            String type = item.getType();
            if (type.equals("slider")) {
                height += 85;
                continue;
            }
            if (type.equals("list")) {
                height += 20 * item.getLines();
            } else {
                height += 25;
            }
        }

        return height;
    }

    private void buildPreferencePanel() {
        errorLabel = new JLabel();
        errorLabel.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
        add(errorLabel, "Center");
        ArrayList tabPanels = new ArrayList();
        JPanel lonePanel = new JPanel();
        lonePanel.setLayout(new BoxLayout(lonePanel, 1));
        lonePanel.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
        tabPanels.add(lonePanel);
        JTabbedPane tabbedPane = null;
        for (int iCtr = 0; iCtr < formFields.length; iCtr++) {
            int addTab = 0;
            ElementPreferences pref = formFields[iCtr];
            String type = pref.getType();
            JPanel itemPanel = new JPanel(new BorderLayout());
            itemPanel.setBorder(BorderFactory.createEmptyBorder(2, 0, 2, 0));
            JLabel label = new JLabel(pref.getTitle());
            itemPanel.add(label, "West");
            label.setPreferredSize(new Dimension(80, 20));
            String value = pref.getDefaultValue();
            if (value == null) {
                value = "";
            }
            if (pref.getValue() != null) {
                value = pref.getValue();
            }
            if (tabbedPane == null && type.equals("tabpane")) {
                tabPanels.remove(0);
                tabbedPane = new JTabbedPane();
                tabbedPane.setPreferredSize(new Dimension(getWidth(), getHeight() - 95));
                ArrayList tabs = pref.getTabsArray();
                for (int jCtr = 0; jCtr < tabs.size(); jCtr++) {
                    String tab = (String) tabs.get(jCtr);
                    JPanel inset = new JPanel(new BorderLayout());
                    JPanel innerPanel = new JPanel();
                    innerPanel.setLayout(new BoxLayout(innerPanel, 1));
                    innerPanel.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
                    inset.add(innerPanel, "North");
                    tabbedPane.addTab(tab, inset);
                    tabPanels.add(innerPanel);
                    addTab = -1;
                }

                componentList.add(tabbedPane);
            } else if (pref.getType().equals("checkbox")) {
                JCheckBox check = new JCheckBox();
                check.setToolTipText(pref.getDescription());
                if (value.equals("true")) {
                    check.setSelected(true);
                } else {
                    check.setSelected(false);
                }
                componentList.add(check);
                itemPanel.add(check, "Center");
                addTab = getTab(tabbedPane, pref.getTabName());
            } else if (pref.getType().equals("spinner")) {
                if (value.length() == 0) {
                    value = "0";
                }
                SpinnerNumberModel model = new SpinnerNumberModel(Integer.parseInt(value), pref.getMinLength(), pref.getMaxLength(), 1);
                JSpinner spinner = new JSpinner(model);
                spinner.setToolTipText(pref.getDescription());
                componentList.add(model);
                itemPanel.add(spinner, "Center");
                addTab = getTab(tabbedPane, pref.getTabName());
            } else if (type.equals("dateSpinner")) {
                SpinnerDateModel model = new SpinnerDateModel();
                JSpinner spinner = new JSpinner(model);
                spinner.setToolTipText(pref.getDescription());
                Calendar calendar = new GregorianCalendar();
                if (value.length() > 0) {
                    calendar.setTimeInMillis(Long.parseLong(value));
                }
                spinner.setValue(calendar.getTime());
                componentList.add(model);
                itemPanel.add(spinner, "Center");
                addTab = getTab(tabbedPane, pref.getTabName());
            } else if (pref.getType().equals("text")) {
                JTextField field = new JTextField(value);
                field.setToolTipText(pref.getDescription());
                componentList.add(field);
                itemPanel.add(field, "Center");
                addTab = getTab(tabbedPane, pref.getTabName());
            } else if (type.equals("password")) {
                JPasswordField field = new JPasswordField(value);
                field.setToolTipText(pref.getDescription());
                componentList.add(field);
                itemPanel.add(field, "Center");
                addTab = getTab(tabbedPane, pref.getTabName());
            } else if (pref.getType().equals("list")) {
                JList list = new JList();
                list.setSelectionMode(0);
                if (pref.getSelect().equals("multiple")) {
                    list.setSelectionMode(2);
                }
                JScrollPane scroller = new JScrollPane();
                scroller.setBackground(new Color(0, 0, 0, 0));
                scroller.getViewport().add(list);
                scroller.setAutoscrolls(true);
                scroller.setPreferredSize(new Dimension(100, 20 * pref.getLines()));
                ArrayList options = pref.getOptionsArray();
                String listData[] = new String[options.size()];
                int selection[] = new int[options.size()];
                int selCtr = 0;
                for (int jCtr = 0; jCtr < options.size(); jCtr++) {
                    listData[jCtr] = (String) options.get(jCtr);
                    if (value.indexOf((String) options.get(jCtr) + ",") > -1 || value.endsWith("," + (String) options.get(jCtr)) || value.equals((String) options.get(jCtr))) {
                        selection[selCtr++] = jCtr;
                    }
                }

                list.setListData(listData);
                list.setSelectedIndices(selection);
                scroller.setToolTipText(pref.getDescription());
                list.setToolTipText(pref.getDescription());
                componentList.add(list);
                itemPanel.add(scroller, "Center");
                addTab = getTab(tabbedPane, pref.getTabName());
            } else if (pref.getType().equals("popup")) {
                JComboBox combo = new JComboBox();
                int selection = 0;
                for (int jCtr = 0; jCtr < pref.getOptionsArray().size(); jCtr++) {
                    combo.addItem((String) pref.getOptionsArray().get(jCtr));
                    if (value.equals((String) pref.getOptionsArray().get(jCtr))) {
                        selection = jCtr;
                    }
                }

                combo.setToolTipText(pref.getDescription());
                combo.setSelectedIndex(selection);
                componentList.add(combo);
                itemPanel.add(combo, "Center");
                addTab = getTab(tabbedPane, pref.getTabName());
            } else if (pref.getType().equals("slider")) {
                if (pref.getValue() == null) {
                    pref.setValue("0");
                }
                JSlider slider = new JSlider();
                slider.setToolTipText(pref.getDescription());
                slider.setMaximum(pref.getMaxLength());
                slider.setMinimum(pref.getMinLength());
                slider.setValue(Integer.parseInt(pref.getValue()));
                slider.setPaintTicks(true);
                slider.setMajorTickSpacing(280 / pref.getTicks());
                slider.setToolTipText(pref.getDescription());
                ArrayList tickLabels = pref.getTickLabels();
                if (tickLabels.size() > 0) {
                    int offset = 255 / tickLabels.size();
                    if (tickLabels.size() > 1) {
                        offset = 255 / (tickLabels.size() - 1);
                    }
                    Hashtable labels = new Hashtable();
                    for (int jCtr = 0; jCtr < tickLabels.size(); jCtr++) {
                        labels.put(new Integer(jCtr * offset), new JLabel((String) tickLabels.get(jCtr), 0));
                    }

                    slider.setLabelTable(labels);
                    slider.setPaintLabels(true);
                }
                componentList.add(slider);
                itemPanel.add(slider, "Center");
                addTab = getTab(tabbedPane, pref.getTabName());
            } else if (pref.getType().equals("selector")) {
                JPanel p3 = new JPanel();
                p3.setLayout(new BorderLayout());
                JTextField field = new JTextField(value);
                field.setToolTipText(pref.getDescription());
                MyButton button = new MyButton(field, "Browse...");
                button.add("field", field);
                button.setActionCommand("browse:" + iCtr);
                button.addActionListener(this);
                p3.add(field, "Center");
                p3.add(button, "East");
                componentList.add(field);
                itemPanel.add(p3, "Center");
                addTab = getTab(tabbedPane, pref.getTabName());
            }
            if (addTab > -1) {
                JPanel boxPanel = (JPanel) tabPanels.get(addTab);
                boxPanel.add(itemPanel);
            }
        }

        if (tabbedPane != null) {
            add(tabbedPane, "North");
        } else {
            JPanel boxPanel = (JPanel) tabPanels.get(0);
            add(boxPanel, "North");
        }
    }

    private int getTab(JTabbedPane tabbedPane, String tabName) {
        int addTab = 0;
        if (tabbedPane != null && tabName != null) {
            for (int jCtr = 0; addTab == 0 && jCtr < tabbedPane.getTabCount(); jCtr++) {
                if (tabbedPane.getTitleAt(jCtr).equals(tabName)) {
                    addTab = jCtr;
                }
            }

        }
        return addTab;
    }

    private boolean isValid(ElementPreferences item, String value) {
        boolean isValid = true;
        if (item.getValidator() != null) {
            try {
                String args[] = new String[1];
                args[0] = value;
                if (widget.executeJavaScriptFunction(item.getValidator(), args) == null) {
                    isValid = false;
                }
            } catch (Exception ex) {
                isValid = false;
            }
        }
        return isValid;
    }

    public void actionPerformed(ActionEvent e) {
        if (e.getActionCommand().equals("Save")) {
            boolean canClose = true;
            for (int offset = 0; offset < formFields.length; offset++) {
                ElementPreferences pref = formFields[offset];
                String type = pref.getType();
                if (type.equals("checkbox")) {
                    JCheckBox check = (JCheckBox) componentList.get(offset);
                    pref.setValue("" + check.isSelected());
                    continue;
                }
                if (type.equals("spinner")) {
                    SpinnerNumberModel model = (SpinnerNumberModel) componentList.get(offset);
                    pref.setValue("" + model.getNumber().intValue());
                    continue;
                }
                if (type.equals("dateSpinner")) {
                    SpinnerDateModel model = (SpinnerDateModel) componentList.get(offset);
                    pref.setValue("" + model.getDate().getTime());
                    continue;
                }
                if (type.equals("text")) {
                    JTextField field = (JTextField/*/JPasswordField*/) componentList.get(offset);
                    if (isValid(pref, field.getText())) {
                        pref.setValue(field.getText());
                    } else {
                        errorLabel.setText(pref.getValidatorMessage());
                        canClose = false;
                    }
                    continue;
                }
                if (type.equals("password")) {
                    JPasswordField field2 = (JPasswordField) componentList.get(offset);
                    String password = new String(field2.getPassword());
                    if (isValid(pref, password)) {
                        pref.setValue(password);
                    } else {
                        errorLabel.setText(pref.getValidatorMessage());
                        canClose = false;
                    }
                    continue;
                }
                if (type.equals("list")) {
                    JList list = (JList) componentList.get(offset);
                    int selects[] = list.getSelectedIndices();
                    ArrayList options = pref.getOptionsArray();
                    String value = "";
                    for (int jCtr = 0; jCtr < selects.length; jCtr++) {
                        if (value.length() > 0) {
                            value = value + ",";
                        }
                        value = value + (String) options.get(selects[jCtr]);
                    }

                    pref.setValue(value);
                    continue;
                }
                if (type.equals("popup")) {
                    JComboBox combo = (JComboBox) componentList.get(offset);
                    pref.setValue((String) pref.getOptionsArray().get(combo.getSelectedIndex()));
                    continue;
                }
                if (pref.getType().equals("slider")) {
                    JSlider slider = (JSlider) componentList.get(offset);
                    pref.setValue("" + slider.getValue());
                    continue;
                }
                if (!type.equals("selector")) {
                    continue;
                }
                JTextField slider = (JTextField) componentList.get(offset);
                if (isValid(pref, slider.getText())) {
                    String fieldValue = Iwidget.replace(slider.getText(), "\\", "/", 0);
                    pref.setValue(fieldValue);
                } else {
                    errorLabel.setText(pref.getValidatorMessage());
                    canClose = false;
                }
            }

            if (canClose) {
                result = "Save";
                dialog.hide();
            }
        } else if (e.getActionCommand().equals("Cancel")) {
            result = "Cancel";
            dialog.hide();
        } else if (e.getActionCommand().startsWith("browse:")) {
            MyButton button = (MyButton) e.getSource();
            int value = Integer.parseInt(e.getActionCommand().substring(7));
            ElementPreferences pref = formFields[value];
            JFileChooser chooser = new JFileChooser(pref.getDirectory());
            try {
                chooser.setSelectedFile(new File((new File(pref.getFile())).getCanonicalPath()));
            } catch (Exception ex) {
            }
            for (int iCtr = 0; iCtr < pref.getExtensions().size(); iCtr++) {
                chooser.addChoosableFileFilter(new MyFilter((String) pref.getExtensions().get(iCtr)));
            }

            if (pref.getKind().equals("files")) {
                chooser.setFileSelectionMode(0);
            } else if (pref.getKind().equals("folders")) {
                chooser.setFileSelectionMode(1);
            } else {
                chooser.setFileSelectionMode(2);
            }
            int returnVal = 0;
            if (pref.getStyle().equals("open")) {
                returnVal = chooser.showOpenDialog(this);
            } else {
                returnVal = chooser.showSaveDialog(this);
            }
            if (returnVal == 0) {
                pref.setValue(chooser.getSelectedFile().getAbsolutePath());
                button.field.setText(chooser.getSelectedFile().getAbsolutePath());
            }
        }
    }

    public String getResult() {
        return result;
    }
    private static final long serialVersionUID = 0x3134313936383333L;
    private WidgetElement widget;
    private ElementPreferences formFields[];
    private ArrayList componentList;
    private String result;
    private JLabel errorLabel;
    private JDialog dialog;
}
